//参考
//lock_guard 与 std::unique_lock
https://mp.weixin.qq.com/s?__biz=Mzk3NTIzODAzNw==&mid=2247483796&idx=1&sn=bd1b5f8665b52a74c9e56f156fce4737&chksm=c51693170da9a9a37b323a31351a62831121145b006ca0b707f8fabf056449714150a301bf45&mpshare=1&scene=23&srcid=0608IWKVutIpUpjyrfAMZZ1F&sharer_shareinfo=e58493167507730c411b16fe3fb81467&sharer_shareinfo_first=e58493167507730c411b16fe3fb81467#rd
//C++11 std::call_once 与其使用场景
https://mp.weixin.qq.com/s?__biz=Mzk3NTIzODAzNw==&mid=2247483797&idx=1&sn=f573039646dda529c5dc7614c60c65c0&chksm=c5bb53faa14f7a4d70de61ca7f8d1a75af7cfa07c0d190837a17b99d47d1c55d9146723526b4&mpshare=1&scene=23&srcid=0608Ooyj7koLPDbB9n535EjW&sharer_shareinfo=65489c1c521e5a81ab4d7c15680baf29&sharer_shareinfo_first=65489c1c521e5a81ab4d7c15680baf29#rd
//C++11 condition_variable 使用场景
https://mp.weixin.qq.com/s?__biz=Mzk3NTIzODAzNw==&mid=2247483798&idx=1&sn=f7701d50b8a7168a5890776b715f2113&chksm=c5ee07dd32a8f1805bfdbf2ba34d259d447e83b15adfc1026bdcd7f3c92022973591b19a1769&mpshare=1&scene=23&srcid=0608valjeSeJgqNCq41ZfVoA&sharer_shareinfo=992e3e98865c23088252dd15c6f2689d&sharer_shareinfo_first=992e3e98865c23088252dd15c6f2689d#rd

#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<functional>
#include<queue>


class ThreadPool {
public:
    void ThreadCall() 
    {
        while (1)
        {
            std::unique_lock<std::mutex> lock(mutex);
            //bool Iswait = stop || (!tasks.empty());
            //condition.wait(lock, Iswait);//Iswait = true就等待，false就继续
            //这个地方wait函数的第二个参数需要是一个谓词，所以不能用上述的写法
            condition.wait(lock, [this] { return !tasks.empty() || stop; });
            if (stop && tasks.empty())   return;
            //move语句：它的功能很简单，就是将某个左值强制转化为右值。
            //eg:c = std::move(a);转移后原对象不再拥有资源，通常变为 “空” 状态。
            std::function<void()> task(std::move(tasks.front()));
            tasks.pop();
            lock.unlock();
            task();
        }
    }
    ThreadPool(int numThreads) :stop(false) {
        for (int i = 0;i < numThreads;i++)
        {
            //threads.push_back(std::thread(ThreadCall));
            threads.emplace_back(&ThreadPool::ThreadCall, this);
        }
    }

    ~ThreadPool()
    {
        {
            std::unique_lock<std::mutex> lock(mutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread& thread : threads)
        {
            thread.join();
        }
    }

    template<typename F,typename...Args>
    void enqueue(F&& f, Args&&... args)
    {   
        //bind函数：
        // 它的作用是将一个可调用对象（比如函数、函数指针、成员函数、成员函数指针等等）以及若干个参数绑定到一个新的函数对象上，形成一个新的可调用对象。
        //std::forward 是 C++11 标准库中的一个函数模板，用于完美转发参数。
        //它的主要作用是在函数模板中将传入的参数按照它们的值类别（左值或右值）进行转发，以保持它们的值类别不变，从而避免不必要的拷贝和移动操作。
        std::function<void()> task(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        {
            std::unique_lock<std::mutex> lock(mutex);
            tasks.emplace(std::move(task));
        }
        condition.notify_one();
    }

private:
    std::vector<std::thread>threads;
    std::queue<std::function<void()>>tasks;
    std::mutex mutex;
    std::condition_variable condition;
    bool stop;
};

void func(int i)
{
    std::cout << "Task " << i << "is running in thread" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Task " << i << "is done" << std::endl;
}

int main() {
    ThreadPool pool(4);
    for (int i = 0;i < 10;i++)
    {
        pool.enqueue(func,i);
    }
    return 0;
}

/*
* 
#include <iostream>
#include <functional>

int add(int a, int b) {
    return a + b;
}

int main() {
    auto add_five = std::bind(add, 5, std::placeholders::_1);
    std::cout << add_five(3) << std::endl; // 输出 8
    return 0;
}
在使用 std::bind 函数时，可以使用占位符来指定哪些参数需要在调用函数对象时传递，哪些参数需要在绑定时传递。常用的占位符有：
_1：表示调用函数对象时的第一个参数。
_2：表示调用函数对象时的第二个参数。
_3：表示调用函数对象时的第三个参数。

一些其他的用法：
例如，如果我们希望在调用函数对象时传递第一个参数和第三个参数，而将第二个参数在绑定时传递，可以这样使用占位符：
auto foo = std::bind(func, std::placeholders::_1, arg2, std::placeholders::_3);

在绑定参数时，也可以使用 std::ref 函数将一个变量包装成一个引用，以便在调用函数对象时使用引用传递。例如：
int x = 42;
auto foo = std::bind(func, std::ref(x), std::placeholders::_1);

除了 std::bind 函数外，C++11 还提供了一个新的语言特性——Lambda 表达式，可以用来替代 std::bind 函数。
Lambda 表达式可以更加灵活地实现函数对象的绑定和参数传递。例如：
auto add_five = [](int x) { return add(5, x); };
std::cout << add_five(3) << std::endl; // 输出 8


std::forward
std::forward 是 C++11 标准库中的一个函数模板，用于完美转发参数。
它的主要作用是在函数模板中将传入的参数按照它们的值类别（左值或右值）进行转发，以保持它们的值类别不变，从而避免不必要的拷贝和移动操作。

*/